#include "../util/poll_set.hpp"
#include "../util/poll_manager.hpp"
#include "../transport/transport_udp.hpp"

#include <boost/make_shared.hpp>
#include <boost/smart_ptr.hpp>
#include <functional>
#include <assert.h>
#include <memory>
#include <unistd.h>


void OnUDPReadable(const TransportPtr& transport);
void readUDPTransport(const TransportPtr& transport);



void OnUDPReadable(const TransportPtr& transport)
{
	(void)transport;
	//assert(udp_transport == transport);

	readUDPTransport(transport);
}

void readUDPTransport(const TransportPtr& transport)
{
	bool reading = true;
	bool has_read_callback = true;

	int size = 1024;
	boost::shared_array<uint8_t> read_buffer;
	read_buffer = boost::shared_array<uint8_t>(new uint8_t[size]);
	uint32_t read_size=size; 

	uint32_t read_filled=0;

	while(has_read_callback)
	{
		assert(read_buffer);	
		uint32_t to_read = read_size - read_filled;
		if(to_read > 0)
		{
			int32_t bytes_read = transport->read(read_buffer.get()+read_filled, to_read);
			//ROS_DEBUG_NAMED("superdebug", "Server connection read %d bytes", bytes_read);	
			TRACE("[INFO] superdebug Server connection read %d bytes", bytes_read);	
			if(bytes_read<0)
			{
				TRACE("[ERROR] Bad read, throw away results and report error");	
				read_buffer.reset();
				read_size = 0;
				read_filled = 0;
				has_read_callback = false;
				break;
			}
			//read ok
			TRACE("[INFO] read_buffer:%s", read_buffer.get());
			read_filled += bytes_read;
		}
		assert((int32_t)read_size>=0);
		assert((int32_t)read_filled>=0);
		//assert(read_filled<=read_size, "read_filled=%d, read_size=%d", read_filled, read_size);
        if(read_filled>read_size)
        {
            TRACE("[ASSERT] read_filled=%d, read_size=%d", read_filled, read_size);
            assert(0);
        }

		if(read_filled==read_size)
		{
				TRACE("[INFO] Finish read, store off the read info in case another read() call is made from within the callback");	
				read_buffer.reset();
				read_size = 0;
				read_filled = 0;
				has_read_callback = false;
				
		}
		else
		{
			break;	
		}
	}
	if(!has_read_callback)
	{
		//transport->disableRead();	
	}
	reading=false;
}

void checkForShutdown()
{
    //给pollmanager用来检测g_shutting_down是否被设置为true
    //如果为true就调用pollmanager的shutdown函数关闭线程等资源
    //但由于这里我是在主线程中主动调用手动关闭的，所以不设置这个应该也行。
    //if(g_shutdown_requested)
    //{
        //Since  this gets run from within a mutex inside PollManager, we need to prevent ourselves from deadlocking with
        //another thread that's already in the middle of shutdown()
        //用于多线程的时候，防止别的线程shutdown一半，这个线程也开始shutdown，然后造成的死锁。
        //所以shutdown之前要检测一下是不是已经被shutdown了。
        //而我这个代码肯定是单线程，所以肯定没问题，因此不需要这个功能
        //boost::recursive_mutex::scoped_try_lock lock(g_shutting_down_mutex, boost::defer_lock);
        //while(!lock.try_lock() && !g_shutting_down)
        //{
        //    ros::WallDuration(0.001).sleep();
        //}
        //if(!g_shutting_down)
        //{
        //    shutdown();
        //}
        //g_shutdown_requested = false;
    //}
}

int main(int argc, char *argv[])
{
    //控制台输出 hello world
    TRACE("[INFO] hello world!");

    TRACE("[INFO] start PollManager...loading...");

    PollManager::instance()->addPollThreadListener(checkForShutdown);
    PollManager::instance()->start();

    TRACE("[INFO] start PollManager...ok!");


    TRACE("[INFO] create udp_transport...");
	TransportUDPPtr udp_transport;
    udp_transport= std::make_shared<TransportUDP>(&PollManager::instance()->getPollSet());
    TRACE("[INFO] ok!");


    //Server: createIncoming
    //Client: connect
	
	//udp port: 9090-10000
    TRACE("[INFO] creatingIncoming...");
	if(!udp_transport->createIncoming(9090, true))
	{
		TRACE("[FATAL] UDPServer Listen failed!");
        TRACE("[BREAK]");assert(0);// ROS_BREAK();	
	}
    TRACE("[INFO] UDPServer Listen success!");

	
	//conn();
	//conn->initialize()
	udp_transport->setReadCallback(OnUDPReadable);

	//conn->read()
	udp_transport->enableRead();

	readUDPTransport(udp_transport);


	while(true)
	{
        usleep(200000);
	}

    TRACE("[INFO] shutdown PollManager...loading...");

    PollManager::instance()->shutdown();

    TRACE("[INFO] shutdown PollManager...ok!");

    return 0;
}






